#include "EShape.h"
#include "EColor.h"
#include "EMath.h"

#include "eCPP.h"
namespace engine
{
//------------------------------------------------------------
// EShape
//------------------------------------------------------------
EShape::EShape( _eShapeType eShapeType) :
m_eShapeType( eShapeType ),
m_vPosition( 0.f, 0.f, 0.f )
{
#ifdef eDEBUG_RENDER
  m_pDebugNode          = NULL;
#endif
}

//------------------------------------------------------------
void EShape::endDebug( ManualObject* pManualObject, int &iNbRefs )
{
#ifdef eDEBUG_RENDER
  if( m_pDebugNode != NULL )
  {
    cASSERT( pManualObject != NULL );
    SceneManager& sceneManager = g_debugRenderer.getCurrentOgreSceneManager();
    m_pDebugNode->detachObject( pManualObject );
    sceneManager.getRootSceneNode()->removeChild( m_pDebugNode );
    --iNbRefs;
    if( iNbRefs == 0 )
      sceneManager.destroyManualObject( pManualObject );
    m_pDebugNode     = NULL;
  }
  EDebugDrawable::endDebug();
#endif // eDEBUG_RENDER
}
//------------------------------------------------------------
// EPlaneShape
//------------------------------------------------------------
EPlaneShape::EPlaneShape(const EVector& vNormal, float fD ) :
EShape( EShape::PLANE_SHAPE ),
m_vNormal( vNormal ),
m_fD( fD )
{

}

//------------------------------------------------------------
// EBoxShape
//------------------------------------------------------------
#ifdef eDEBUG_RENDER
ManualObject* EBoxShape::s_pDebugManualObject    = NULL;
int           EBoxShape::s_iNbRefs               = 0;
#endif // eDEBUG_RENDER

//------------------------------------------------------------
EBoxShape::EBoxShape( const EVector& vDimensions ) :
EShape( EShape::BOX_SHAPE ),
m_vDimensions( vDimensions )
{
}

//------------------------------------------------------------
void EBoxShape::startDebug()
{
#ifdef eDEBUG_RENDER
  EDebugDrawable::startDebug();
  SceneManager& sceneManager = g_debugRenderer.getCurrentOgreSceneManager();
  if( s_pDebugManualObject == NULL )
  {
    s_pDebugManualObject = sceneManager.createManualObject("_debug_box_" + StringConverter::toString(s_iNbRefs) );
    cASSERT( s_pDebugManualObject != NULL );
    EVector vPos0( 0.f, 0.f, 0.f );
    EVector vPos1( 0.f, 0.f, 0.f );
    EVector vPos2( 0.f, 0.f, 0.f );
    EVector vPos3( 0.f, 0.f, 0.f );
    float fXDiv2  = m_vDimensions.x * .5f;
    float fYDiv2  = m_vDimensions.y * .5f;
    float fZDiv2  = m_vDimensions.z * .5f;
    float fY      = m_vDimensions.y;

    vPos0 = EVector( -fXDiv2, -fYDiv2, -fZDiv2 );
    vPos1 = EVector( -fXDiv2, -fYDiv2, fZDiv2 );
    vPos2 = EVector( fXDiv2, -fYDiv2, fZDiv2 );
    vPos3 = EVector( fXDiv2, -fYDiv2, -fZDiv2 );

    EVector vPos4( vPos0 );
    EVector vPos5( vPos1 );
    EVector vPos6( vPos2 );
    EVector vPos7( vPos3 );
    vPos4.y += fY;
    vPos5.y += fY;
    vPos6.y += fY;
    vPos7.y += fY;
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_LIST );
    {
      //
      s_pDebugManualObject->position( vPos0 );
      s_pDebugManualObject->colour( getDebugColor() );
      s_pDebugManualObject->position( vPos1 );

      s_pDebugManualObject->position( vPos1 );
      s_pDebugManualObject->position( vPos2 );

      s_pDebugManualObject->position( vPos2 );
      s_pDebugManualObject->position( vPos3 );

      s_pDebugManualObject->position( vPos3 );
      s_pDebugManualObject->position( vPos0 );

      //
      s_pDebugManualObject->position( vPos4 );
      s_pDebugManualObject->position( vPos5 );

      s_pDebugManualObject->position( vPos5 );
      s_pDebugManualObject->position( vPos6 );

      s_pDebugManualObject->position( vPos6 );
      s_pDebugManualObject->position( vPos7 );

      s_pDebugManualObject->position( vPos7 );
      s_pDebugManualObject->position( vPos4 );

      //
      s_pDebugManualObject->position( vPos0 );
      s_pDebugManualObject->position( vPos4 );

      s_pDebugManualObject->position( vPos1 );
      s_pDebugManualObject->position( vPos5 );

      s_pDebugManualObject->position( vPos2 );
      s_pDebugManualObject->position( vPos6 );

      s_pDebugManualObject->position( vPos3 );
      s_pDebugManualObject->position( vPos7 );
    }
    s_pDebugManualObject->end();
  }
  
  m_pDebugNode = sceneManager.getRootSceneNode()->createChildSceneNode( m_vPosition );
  m_pDebugNode->attachObject( s_pDebugManualObject );
  cASSERT( m_pDebugNode != NULL );

  s_iNbRefs++;

#endif // eDEBUG_RENDER
}

//------------------------------------------------------------
void EBoxShape::endDebug()
{
  EShape::endDebug( s_pDebugManualObject, s_iNbRefs );
}

//------------------------------------------------------------
// ECapsuleShape
//------------------------------------------------------------
#ifdef eDEBUG_RENDER
ManualObject* ECapsuleShape::s_pDebugManualObject    = NULL;
int           ECapsuleShape::s_iNbRefs               = 0;
#endif // eDEBUG_RENDER

//------------------------------------------------------------
ECapsuleShape::ECapsuleShape( float fRadius, float fHeight ) :
EShape( EShape::CAPSULE_SHAPE ),
m_fRadius( fRadius ),
m_fHeight( fHeight )
{
  cASSERT( m_fRadius > 0.f );
  cASSERT( m_fHeight > 2.f * m_fRadius );
}

//------------------------------------------------------------
void ECapsuleShape::startDebug()
{
#ifdef eDEBUG_RENDER

  static const int    iNbSegments         = 20;

  EDebugDrawable::startDebug();
  SceneManager& sceneManager = g_debugRenderer.getCurrentOgreSceneManager();
  if( s_pDebugManualObject == NULL )
  {
    s_pDebugManualObject = sceneManager.createManualObject("_debug_capsule_" + StringConverter::toString(s_iNbRefs) );
    cASSERT( s_pDebugManualObject != NULL );

    float fAngleStep    = EMath::fPI / (float)iNbSegments;
    float fCenterHeight = m_fHeight * .5f - m_fRadius;

    // yOz Bottom
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = EMath::fPI_2;
      EVector vPrevious( 0.f, EMath::cos( fAngle ) * m_fRadius - fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( 0.f, EMath::cos( fAngle ) * m_fRadius - fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    // yOz Top
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = -EMath::fPI_2;
      EVector vPrevious( 0.f, EMath::cos( fAngle ) * m_fRadius + fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( 0.f, EMath::cos( fAngle ) * m_fRadius + fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    // xOy Bottom
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = EMath::fPI;
      EVector vPrevious( EMath::cos( fAngle ) * m_fRadius, EMath::sin( fAngle ) * m_fRadius - fCenterHeight, 0.f );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( EMath::cos( fAngle ) * m_fRadius, EMath::sin( fAngle ) * m_fRadius - fCenterHeight, 0.f );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    // xOy Top
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = 0.f;
      EVector vPrevious( EMath::cos( fAngle ) * m_fRadius, EMath::sin( fAngle ) * m_fRadius + fCenterHeight, 0.f );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( EMath::cos( fAngle ) * m_fRadius, EMath::sin( fAngle ) * m_fRadius + fCenterHeight, 0.f );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    /*// xOz Top
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = 0.f;
      EVector vPrevious( EMath::cos( fAngle ) * m_fRadius, fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments*2; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( EMath::cos( fAngle ) * m_fRadius, fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    // xOz Bottom
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = 0.f;
      EVector vPrevious( EMath::cos( fAngle ) * m_fRadius, -fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments*2; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( EMath::cos( fAngle ) * m_fRadius, -fCenterHeight, EMath::sin( fAngle ) * m_fRadius );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();*/

    // xOz Center
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = 0.f;
      EVector vPrevious( EMath::cos( fAngle ) * m_fRadius, 0.f, EMath::sin( fAngle ) * m_fRadius );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments*2; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( EMath::cos( fAngle ) * m_fRadius, 0.f, EMath::sin( fAngle ) * m_fRadius );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    // Length segments
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_LIST );
    {
      s_pDebugManualObject->position(-m_fRadius, -fCenterHeight, 0.f);
      s_pDebugManualObject->colour( getDebugColor() );
      s_pDebugManualObject->position(-m_fRadius, fCenterHeight, 0.f);

      s_pDebugManualObject->position(m_fRadius, -fCenterHeight, 0.f);
      s_pDebugManualObject->colour( getDebugColor() );
      s_pDebugManualObject->position(m_fRadius, fCenterHeight, 0.f);

      s_pDebugManualObject->position(0.f, -fCenterHeight, -m_fRadius);
      s_pDebugManualObject->colour( getDebugColor() );
      s_pDebugManualObject->position(0.f, fCenterHeight, -m_fRadius);

      s_pDebugManualObject->position(0.f, -fCenterHeight, m_fRadius);
      s_pDebugManualObject->colour( getDebugColor() );
      s_pDebugManualObject->position(0.f, fCenterHeight, m_fRadius);
    }
    s_pDebugManualObject->end();
  }
  m_pDebugNode = sceneManager.getRootSceneNode()->createChildSceneNode( m_vPosition );
  m_pDebugNode->attachObject( s_pDebugManualObject );
  cASSERT( m_pDebugNode != NULL );

  s_iNbRefs++;

#endif // eDEBUG_RENDER
}

//------------------------------------------------------------
void ECapsuleShape::endDebug()
{
  EShape::endDebug( s_pDebugManualObject, s_iNbRefs );
}

//------------------------------------------------------------
// ESphereShape
//------------------------------------------------------------
#ifdef eDEBUG_RENDER
ManualObject* ESphereShape::s_pDebugManualObject    = NULL;
int           ESphereShape::s_iNbRefs               = 0;
#endif // eDEBUG_RENDER

//------------------------------------------------------------
ESphereShape::ESphereShape(float fRadius ) :
EShape( EShape::SPHERE_SHAPE ),
m_fRadius( fRadius )
{
  cASSERT( m_fRadius > 0.f );
}

//------------------------------------------------------------
void ESphereShape::startDebug()
{
#ifdef eDEBUG_RENDER

  static const int    iNbSegments         = 30;

  EDebugDrawable::startDebug();
  SceneManager& sceneManager = g_debugRenderer.getCurrentOgreSceneManager();
  if( s_pDebugManualObject == NULL )
  {
    s_pDebugManualObject = sceneManager.createManualObject("_debug_sphere_" + StringConverter::toString(s_iNbRefs) );
    cASSERT( s_pDebugManualObject != NULL );
    
    float fAngleStep = EMath::f2PI / (float)iNbSegments;

    // xOz
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = 0.f;
      EVector vPrevious( EMath::cos( fAngle ), 0.f, EMath::sin( fAngle ) );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( EMath::cos( fAngle ), 0.f, EMath::sin( fAngle ) );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    // yOz
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = 0.f;
      EVector vPrevious( 0.f, EMath::cos( fAngle ), EMath::sin( fAngle ) );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( 0.f, EMath::cos( fAngle ), EMath::sin( fAngle ) );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();

    // xOy
    s_pDebugManualObject->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP );
    {
      float fAngle = 0.f;
      EVector vPrevious( EMath::cos( fAngle ), EMath::sin( fAngle ), 0.f );
      s_pDebugManualObject->position( vPrevious );
      s_pDebugManualObject->colour( getDebugColor() );
      for( int i=0; i<iNbSegments; ++i )
      {
        fAngle += fAngleStep;
        EVector vCurrent( EMath::cos( fAngle ), EMath::sin( fAngle ), 0.f );
        s_pDebugManualObject->position( vCurrent );
      }
    }
    s_pDebugManualObject->end();
  }
  m_pDebugNode = sceneManager.getRootSceneNode()->createChildSceneNode( m_vPosition );
  m_pDebugNode->setScale( m_fRadius, m_fRadius, m_fRadius );
  m_pDebugNode->attachObject( s_pDebugManualObject );
  cASSERT( m_pDebugNode != NULL );

  s_iNbRefs++;

#endif // eDEBUG_RENDER
}

//------------------------------------------------------------
void ESphereShape::endDebug()
{
  EShape::endDebug( s_pDebugManualObject, s_iNbRefs );
}

//------------------------------------------------------------
// ETriangleMeshShape
//------------------------------------------------------------
ETriangleMeshShape::ETriangleMeshShape(const MeshPtr& ogreMeshPtr) :
EShape( EShape::TRIANGLE_MESH_SHAPE ),
m_ogreMeshPtr( ogreMeshPtr )
{

}

} // end namespace